算法基础 1
· 阅读需 4 分钟
https://oi-wiki.org/dp/knapsack/#0-1-背包
0-1 背包问题是指有一个固定大小、能够携带重量为 W 的背包,以及一组有价值和重量的物品,需要决定将哪些物品放入背包中,以便在不超过背包容量的前提下,让背包中的总价值最大。
状态转移方程
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i])
其中 dp[i][j]
表示前 i
件物品放入容量为 j
的背包可以获得的最大价值,w[i]
和 v[i]
分别表示第 i
件物品的重量和价值。
优化
将二维数组压缩为一维数组,即 dp[j] = max(dp[j], dp[j - w[i]] + v[i])
。这是 因为当前状态只与上一个状态有关,因此可以使用滚动数组来优化空间复杂度。
例题
LeetCode 416
https://leetcode.com/problems/partition-equal-subset-sum/
题意:给定一个只包含正整数的非空数组,判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
答:转移方程为 dp[i][j] = dp[i-1][j] or dp[i-1][j-nums[i]]
,其中 dp[i][j]
表示前 i
个数组成的数组,其某个子集的和是否等于 j
,再配合滚动数组优化变为 1d DP
。
核心代码:
dp = [False] * (half_s + 1)
dp[0] = True
for num in nums:
for j in range(half_s, num - 1, -1):
dp[j] = dp[j] or dp[j - num]